﻿using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using log4net;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using YZAutoDWR.Data;
using YZAutoDWR.Entity;
using YZAutoDWR.Response;

namespace YZAutoDWR.Handler;

public class WeWorkHandler
{
    private readonly DWRDbContext _db;
    private static readonly ILog Log = LogManager.GetLogger(typeof(App));
    private static string? _platformUrl;
    private static string? _userAccount;
    private static string? _userPassword;
    private const string CurrentToken = ""; // 存储当前的 Token
    private static readonly DateTime TokenExpiryTime = DateTime.MinValue; // Token 过期时间（UTC）
    private readonly ResponseContent _responseContent = new();

    public WeWorkHandler
        (DWRDbContext dbContext)
    {
        _db = dbContext;
    }

    private async void GetUserConfig()
    {
        var userConfig = await _db.UserConfig.FirstOrDefaultAsync(x => x.Id == 1);
        if (userConfig == null)
        {
            Console.WriteLine("用户配置获取异常");
            Log.Error("用户配置获取异常");
        }
        else
        {
            _platformUrl = userConfig.PlatformUrl;
            _userAccount = userConfig.UserAccount;
            _userPassword = userConfig.UserPassword;
        }
    }

    /// <summary>
    /// 更新个人名下的所有工单信息
    /// </summary>
    /// <param name="selectType">"2" 获取 "指派给我" 的工单; "3" 获取 "由我解决" 的工单</param>
    /// <returns></returns>
    /// <exception cref="InvalidOperationException"></exception>
    public async Task<ResponseContent> UpdateWorkOrderList(int selectType)
    {
        GetUserConfig();
        var ticketContent = await GetTicketList(selectType.ToString());
        var jsonObject = JObject.Parse(ticketContent);
        var workOrderList = jsonObject["data"]?["data"]?.ToObject<List<WorkOrderEntity>>();

        if (workOrderList == null || workOrderList.Count == 0) throw new InvalidOperationException("未找到可处理的工单数据");

        foreach (var workOrder in workOrderList.Where(workOrder => !string.IsNullOrWhiteSpace(workOrder.Id)))
        {
            var existing = await _db.WorkOrder.FindAsync(workOrder.Id);

            if (existing == null)
            {
                await _db.WorkOrder.AddAsync(workOrder);
                continue;
            }

            var json = JsonConvert.SerializeObject(workOrder);
            JsonConvert.PopulateObject(json, existing);
            _db.WorkOrder.Update(existing);
        }

        var effectRow = await _db.SaveChangesAsync();
        return effectRow == 0 ? _responseContent.Error("工单信息获取成功, 但本地数据更新失败") : _responseContent.OK();
    }

    /// <summary>
    /// 获取工单列表
    /// </summary>
    /// <param name="selectType">"2" 获取 "指派给我" 的工单; "3" 获取 "由我解决" 的工单</param>
    /// <returns></returns>
    /// <exception cref="Exception"></exception>
    private async Task<string> GetTicketList(string selectType)
    {
        var token = await GetPlatformToken();
        if (string.IsNullOrEmpty(token))
        {
            throw new Exception("从工单平台获取到的 Token 为空");
        }

        const string operation = ":6199/ticket/WorkOrder/GetTicketList";
        var apiUrl = _platformUrl?.TrimEnd('/') + operation;
        var requestData = new
        {
            pageIndex = 1,
            pageSize = 200,
            sidx = "o.processedTime",
            sort = "desc",
            keyword = "",
            ticketType = "",
            state = Array.Empty<string>(),
            startTime = "",
            endTime = "",
            selectType,
            productId = "538274777854021",
            assignUser = Array.Empty<string>(),
            disposeStartTime = "",
            disposeEndTime = "",
            IsSelectCustomer = false
        };

        using var client = new HttpClient();
        client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token}");

        var jsonContent = JsonConvert.SerializeObject(requestData);
        var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

        var response = await client.PostAsync(apiUrl, content);
        if (!response.IsSuccessStatusCode)
        {
            Log.Error("工单平台请求失败" + $"请求地址 {apiUrl} 状态码: {response.StatusCode} ({(int)response.StatusCode})");
            throw new Exception($"工单平台请求失败, 请求地址:\n{apiUrl} \n状态码: {response.StatusCode} ({(int)response.StatusCode})");
        }

        var ticketContent = await response.Content.ReadAsStringAsync();

        return ticketContent;
    }

    /// <summary>
    /// 获取工单平台的 Token, Token 无效时通过登录接口重新获取
    /// </summary>
    private async Task<string> GetPlatformToken()
    {
        if (!string.IsNullOrEmpty(CurrentToken) && DateTime.UtcNow < TokenExpiryTime)
        {
            return CurrentToken;
        }

        const string operation = ":6199/CS/User/Login";
        var loginUrl = _platformUrl?.TrimEnd('/') + operation;
        var loginData = new { username = _userAccount, password = _userPassword };

        using var client = new HttpClient();
        var jsonContent = JsonConvert.SerializeObject(loginData);
        var content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

        var response = await client.PostAsync(loginUrl, content);
        if (!response.IsSuccessStatusCode)
        {
            this.ShowToast("工单平台登录失败", $"请求地址:\n{loginUrl} \n状态码: {response.StatusCode} ({(int)response.StatusCode})");
            Log.Error("工单平台登录失败" + $"请求地址: {loginUrl} 状态码: {response.StatusCode} ({(int)response.StatusCode})");
            throw new Exception($"登录失败: {response.StatusCode}");
        }

        var responseBody = await response.Content.ReadAsStringAsync();
        var jsonResponse = JsonConvert.DeserializeObject<dynamic>(responseBody);
        if (jsonResponse?.code != 200)
        {
            Log.Error("工单平台请求失败" + $"{jsonResponse?.msg}");
            throw new HttpRequestException("工单平台请求失败" + $"{jsonResponse?.msg}");
        }

        string newToken = jsonResponse.data.ToString() ?? throw new InvalidOperationException();

        if (IsValidJwt(newToken)) return newToken;
        throw new Exception("无效的 JWT 格式");
    }

    private static bool IsValidJwt(string token)
    {
        var handler = new JwtSecurityTokenHandler();
        return handler.CanReadToken(token) && token.Count(c => c == '.') == 2;
    }
}